#ifndef PRODUCT_PARAM_H
#define PRODUCT_PARAM_H


#include <string>
#include <vector>
#include "spdlog/spdlog.h"
#include "spdlog/sinks/daily_file_sink.h"
#include "./sharedcodes-87/ajson5.h"
#include <iostream>
#include "gdal_priv.h"
#include "wGdalRaster.h"

using namespace ArduinoJson;
using std::ifstream;
using std::string;
using std::vector ;

struct GParams{
    string gdaltranslate,gdalwarp; 
    string host,user,pwd,db;    
    string plotcmd ;
    string log ;
} ;


struct PlotParam
{
	string pid ;//入库产品id
    string tag ;//文件名tag
	string temfile ;//绘图模板文件
} ;

struct QhcDataGroup{
    bool isok=false;
    vector<string> monqhc ;
    vector<string> seaqhc ;
    vector<string> yeaqhc ;
    bool getQhcData(const string type,const int targetYmd,vector<short>& retQhcData) ;
    bool loadFromJsonObject( JsonObject& obj) ;
} ;


//read string array from parent json object by arrayName 
// e.g. { ... , "somearr":[...] , ....}
// vector<string> values=loadJsonStringArray(root , "somearr") ;
vector<string> loadJsonStringArray( JsonObject& parentObj, string arrayName){
	std::vector<string> res;
	if( parentObj.containsKey(arrayName.c_str()) ){
		JsonArray& arr = parentObj[arrayName.c_str()].as<JsonArray>() ;
		for(int it = 0 ; it < arr.size() ; ++ it )
		{
			string str1 = arr[it].as<char*>() ;
			res.push_back(str1) ;
		}
	}
	return res ;
}

//加载绘图参数数组               
vector<PlotParam> loadPlotParamArray( JsonObject& parentObj, string arrayName){
	std::vector<PlotParam> res;
	if( parentObj.containsKey(arrayName.c_str()) ){
		JsonArray& arr = parentObj[arrayName.c_str()].as<JsonArray>() ;
		for(int it = 0 ; it < arr.size() ; ++ it )
		{
			JsonObject& obj1 = arr[it].as<JsonObject>() ;
			PlotParam plotp ;
			plotp.pid = obj1["pid"].as<char*>() ;
			plotp.tag = obj1["tag"].as<char*>() ;
			plotp.temfile = obj1["temfile"].as<char*>() ;
			res.push_back(plotp) ;
		}
	}
	return res ;
}



bool QhcDataGroup::getQhcData(
    const string type,  // mon, sea, yea
    const int inputYmd, // yyyyMMdd , e.g. 20010131 , use input ymd to find corresponding qhc data. 
    vector<short>& retQhcData
    ) 
{
    if( isok==false ){
        spdlog::critical("QhcDataGroup::getQhcData, QhcDataGroup is not initialized.") ;
        return false ;
    }
    int month = (inputYmd%10000)/100 ;
    string qhcfile = "" ;
    if( type=="mon" ){
        int index = month-1 ;//0,1,2...,11
        qhcfile = monqhc[index] ;
    }
    else if( type=="sea" ){
        int index = month/3 - 1 ;// 0,1,2,3
        qhcfile = seaqhc[index] ;
    }
    else {
        qhcfile = yeaqhc[0] ;//only one
    }
    wGdalRasterI16 qhcdata ;
    bool openok = qhcdata.open(qhcfile) ;
    if( openok ==false ){
        spdlog::critical("QhcDataGroup::getQhcData, read data from qhc file failed '{}'.", qhcfile) ;
        return false ;
    }
    int asize = qhcdata.getXSize() * qhcdata.getYSize() ;
    retQhcData.resize(asize) ;
    for(int it=0;it<asize;++it) retQhcData[it] = qhcdata.getValuei(it,0) ;
    return true ;
}


//产品生产参数
struct ProductParam
{
    inline ProductParam(){enabled=0;}
	int enabled;
	string type;//day,mon,sea,yea
	int ymdloc; // 在文件名中yyyymmdd开始的字符
    int ymdlen; //fy4 =8 , ims=7
	string indir;
	string inprefix;
	string intail;
	string outdir;
	string xlpid;//序列产品ID
	string pname;//产品名称
    string outprefix;//输出文件名前缀
    vector<string> maskfiles ;//面积指数计算区域mask文件数组
    vector<PlotParam> plots ;//控件绘图PID和绘图模板
    void loadFromJsonObject(JsonObject& obj) ;
};

void ProductParam::loadFromJsonObject(JsonObject& obj) 
{
    this->enabled = obj["enabled"].as<int>();
    this->type = obj["type"].as<char*>();
    this->ymdloc = obj["ymdloc"].as<int>();
    this->ymdlen = obj["ymdlen"].as<int>();
    this->indir = obj["indir"].as<char*>();
    this->inprefix = obj["inprefix"].as<char*>();
    this->intail = obj["intail"].as<char*>();
    this->outdir = obj["outdir"].as<char*>();
    this->xlpid = obj["xlpid"].as<char*>();
    this->pname = obj["pname"].as<char*>();
    this->outprefix = obj["outprefix"].as<char*>();
    this->maskfiles = loadJsonStringArray( obj , "maskfiles") ;
    this->plots = loadPlotParamArray(obj, "plots") ;
}

void loadJsonParams(
    string jsonfile, 
    GParams& gpp ,//global params
    ProductParam& fy4daypp, 
    ProductParam& imsdaypp, 
    vector<ProductParam>& level3pp,
    vector<ProductParam>& jupingpp,
    QhcDataGroup& qhcGroup
)
{
	std::ifstream ifs(jsonfile.c_str());
	ArduinoJson::DynamicJsonBuffer jsonBuffer;
	ArduinoJson::JsonVariant root = jsonBuffer.parseObject(ifs);

	{//global
		gpp.gdaltranslate = root["gdaltranslate"].as<char*>();
		gpp.gdalwarp = root["gdalwarp"].as<char*>();
        gpp.host = root["host"].as<char*>();
		gpp.user = root["user"].as<char*>();
		gpp.pwd = root["pwd"].as<char*>();
		gpp.db = root["db"].as<char*>();
        gpp.plotcmd = root["plotcmd"].as<char*>();
        gpp.log = root["log"].as<char*>() ;
	}

	//fy4day
	{
		JsonObject& obj = root["fy4day"].as<JsonObject>() ;
		fy4daypp.loadFromJsonObject(obj) ;
	}

	//ims snow
	{
		JsonObject& obj = root["imsday"].as<JsonObject>();
		imsdaypp.loadFromJsonObject(obj) ;
	}

	JsonArray& l3arr = root["level3"].as<JsonArray>() ;
	for (int i = 0; i < l3arr.size(); ++i)
	{
		JsonObject& obj = l3arr[i];
		ProductParam pp;
        pp.loadFromJsonObject(obj) ;
		level3pp.push_back(pp);
	}
    
    JsonArray& jparr = root["juping"].as<JsonArray>() ;
    for (int i = 0; i < jparr.size(); ++i)
	{
		JsonObject& obj = jparr[i];
		ProductParam pp;
        pp.loadFromJsonObject(obj) ;
		jupingpp.push_back(pp);
	}
    
    JsonObject& qhc = root["imsqhcgroup"].as<JsonObject>() ;
    bool qhcok = qhcGroup.loadFromJsonObject(qhc) ;
    if( qhcok ==false ){
        spdlog::warn("load imsqhcgroup failed.") ;
    }else{
        spdlog::info("load imsqhcgroup success.") ;
    }
    
	ifs.close();
}





bool QhcDataGroup::loadFromJsonObject( JsonObject& obj) 
{
    isok = false ;
    monqhc = loadJsonStringArray(obj,"mon") ;
    seaqhc = loadJsonStringArray(obj,"sea") ;
    yeaqhc = loadJsonStringArray(obj,"yea") ;
    if( monqhc.size()==12 && seaqhc.size()==4 && yeaqhc.size()==1 ){
        isok = true ;
    }else{
        isok = false;
    }
    return isok ;
}



#endif